<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<style>
			html,
			body {
				position: relative;
				margin: 0;
				padding: 0;
				width: 100%;
				height: 100%;
				overflow: hidden;
				user-select: none;
			}

			html {
				font-size: 16px;
				line-height: 1;
			}

			body {
				background-color: #edf2f7;
			}

			.block {
				display: block;
				position: absolute;
				width: 300px;
				height: 200px;
				border-radius: 8px;
				box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07),
					0 2px 4px rgba(0, 0, 0, 0.07),
					0 4px 8px rgba(0, 0, 0, 0.07),
					0 8px 16px rgba(0, 0, 0, 0.07),
					0 16px 32px rgba(0, 0, 0, 0.07),
					0 32px 64px rgba(0, 0, 0, 0.07);
				background-color: #FFF;
				cursor: grab;
			}
		</style>
	</head>
	<body>
		<!-- 可移动元素 -->
		<div id="block" class="block" style="left:0px;top:0px;"></div>
		<a href="https://www.bilibili.com/read/cv25534268">源代码地址</a>
		<script type="text/javascript">
			/**
			 * 思路解析
			 * 1.记录元素移动后的坐标
			 * 2.页面坐标 -> 屏幕坐标, 发送给所有人和自己
			 * 3.获取到坐标，屏幕坐标 -> 页面坐标， 进行更新
			 */
			(function() {
				const block = document.getElementById("block");
				// 跨标签通信广播
				const channel = new BroadcastChannel("DataTransfer");

				/**
				 * @description 坐标转换函数
				 * @param {string} type
				 * @param {object} coords
				 * 例: { x: number, y: number }
				 */
				function convertCoords(type, coords) {
					let { x, y } = coords;
					let { screenLeft, screenTop } = window;
					return ({
						// 页面坐标 -> 屏幕坐标
						"p2s": {
							x: x + screenLeft,
							y: y + screenTop,
						},
						// 屏幕坐标 -> 页面坐标
						"s2p": {
							x: x - screenLeft,
							y: y - screenTop,
						}
					} [type] || { x: 0, y: 0 });
				}
				/**
				 * @description 处理元素坐标更新
				 * @param {object} data
				 * 例：{ x: number, y: number }
				 */
				function handleUpdateCoords(data) {
					// 屏幕坐标 -> 页面坐标
					const { x, y } = convertCoords("s2p", data);
					block.style.left = x + "px";
					block.style.top = y + "px";
				}
				/**
				 * @description 初始化元素坐标
				 */
				function initElementCoords() {
					const elementW = block.clientWidth;
					const elementH = block.clientHeight;
					const windowW = window.innerWidth;
					const windowH = window.innerHeight;
					block.style.left = Math.round(windowW / 2 - elementW / 2) + "px";
					block.style.top = Math.round(windowH / 2 - elementH / 2) + "px";
				}
				/**
				 * @description 解析广播信息
				 * @param {MessageEvent<ChannelMessage>} event
				 * @returns {ChannelMessage} 
				 */
				// 元素拖拽
				block.addEventListener("mousedown", (downEvent) => {
					/** 元素相对于屏幕的坐标 */
					let elementCoords = convertCoords('p2s', {
						x: parseInt(block.style.left),
						y: parseInt(block.style.top),
					});

					/** 元素起始水平坐标 */
					let elementX = elementCoords.x;

					/** 元素起始垂直坐标 */
					let elementY = elementCoords.y;

					/** 鼠标起始水平坐标 */
					let cursorX = downEvent.screenX;

					/** 鼠标起始垂直坐标 */
					let cursorY = downEvent.screenY;

					/**
					 * @description 处理鼠标移动
					 * @param {MouseEvent} moveEvent
					 */
					let handleMove = function(moveEvent) {
						//  计算元素移动后的距离
						let newX = elementX + (moveEvent.screenX - cursorX);
						let newY = elementY + (moveEvent.screenY - cursorY);

						let coords = { x: newX, y: newY };

						// 更新当前页面元素坐标
						handleUpdateCoords(coords);

						// 通知其他页面
						channel.postMessage(coords);
					};

					let handleUp = function() {
						window.removeEventListener('mousemove', handleMove);
						window.removeEventListener('mouseup', handleUp);
					};

					window.addEventListener('mousemove', handleMove);
					window.addEventListener('mouseup', handleUp);
				});
				// 处理广播
				channel.addEventListener("message", (ev) => {
					const { data } = ev;
					handleUpdateCoords(data);
				});

				initElementCoords();
			})();
		</script>
	</body>
</html>